/* 模块：bits_indicator
 * 类型：基础结构
 * 功能：提供静态/动态的位图结构
 * 用法：
 * TODO======================================================================================
 */

// 注意:
// 需要确保经过指定元素类型的位图在 32bt/64bit 具有相同的存储模型
// level_lut 也需要保持一致
#ifndef xpack_utils_bits_indicator
#define xpack_utils_bits_indicator
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_bits_indicator::inc
#include"adapter/bits_indicator.hpp"
#include"concurrency/lock/atom_swap.hpp"
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"interface/can_alloc.hpp"
#include"macro/xexport.hpp"
#include"memop/zeros.hpp"
#include"meta/is_unsigned.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_bits_indicator::origin{
    template<inc::is_unsigned unsigned_t, uxx bits_v = 0>
    struct bits_indicator_tmpl;

    /* 结构：静态位图
     * 参数：
     * - bits_v 为总位数
     */
    template<inc::is_unsigned unsigned_t, uxx bits_v>
    xstruct(
        xtmpl(bits_indicator_tmpl, unsigned_t, bits_v),
        xpubb(inc::bits_indicator<bits_indicator_tmpl<unsigned_t, bits_v>>)
    )
    private:
        static constexpr unsigned_t bits = xbitsof(unsigned_t);
        static constexpr unsigned_t lv0 = bits_v / bits + (bits_v % bits != 0);
        static constexpr unsigned_t lv1 = lv0 <= 1 ? 0 : lv0 / bits + (lv0 % bits != 0);
        static constexpr unsigned_t lv2 = lv1 <= 1 ? 0 : lv1 / bits + (lv1 % bits != 0);
        static constexpr unsigned_t lv3 = lv2 <= 1 ? 0 : lv2 / bits + (lv2 % bits != 0);
        static constexpr unsigned_t lv4 = lv3 <= 1 ? 0 : lv3 / bits + (lv3 % bits != 0);
        static constexpr unsigned_t lv5 = lv4 <= 1 ? 0 : lv4 / bits + (lv4 % bits != 0);
        static constexpr unsigned_t lv6 = lv5 <= 1 ? 0 : lv5 / bits + (lv5 % bits != 0);
        static constexpr unsigned_t lv7 = lv6 <= 1 ? 0 : lv6 / bits + (lv6 % bits != 0);
        static constexpr unsigned_t lv8 = lv7 <= 1 ? 0 : lv7 / bits + (lv7 % bits != 0);
        static constexpr unsigned_t lv9 = lv8 <= 1 ? 0 : lv8 / bits + (lv8 % bits != 0);
        static constexpr unsigned_t totol_size = lv0 + lv1 + lv2 + lv3 + lv4 + lv5 + lv6 + lv7 + lv8 + lv9;
        static constexpr unsigned_t lut[] = { lv0,lv1,lv2,lv3,lv4,lv5,lv6,lv7,lv8,lv9 };
        static_assert(bits_v <= u32(-1)); // 需要小于 32bit 最大值
    public:
        xprops()
            friend inc::bits_indicator<the_t>;

            /* 位图可访问的总位数 */
            xpubgetx(total_bits, unsigned_t){
                xr{ return bits_v; }
            };

            /* 属性：位图树每一级的元素个数
             * 补充：lut[0] 表示第一级位图字的个数，对于 64bit 系统一个字有 64bit
             *       位图是分层的，在 64bit 系统，上层用 1bit 表示下层 64bit 位组中是否有置位位
             *       该属性的每一个元素分别指示了每次层一共有多少个字
             */
            xprogetx(level_lut, const unsigned_t *){
                xr{ return the_t::lut; }
            };

            /* 属性：位图树中一共包含的字数 */
            xprogetx(size, unsigned_t){
                xr{ return totol_size; }
            };

            /* 属性：位图树的高度 */
            xprogetx(height, unsigned_t){
                xr{
                    return 
                        lv9 ? 10 : 
                        lv8 ? 9  : 
                        lv7 ? 8  : 
                        lv6 ? 7  : 
                        lv5 ? 6  : 
                        lv4 ? 5  : 
                        lv3 ? 4  : 
                        lv2 ? 3  : 
                        lv1 ? 2  : 1;
                }
            };

            /* 属性：位图的首地址 */
            xprogetx(bmp, unsigned_t *){
                xr{ return xthe.data; }
            };
        $

        xprops_operator()

    private:
        mutable unsigned_t data[totol_size] = {0};
    $

    /* 结构：动态位图
     */
    template<inc::is_unsigned unsigned_t>
    xstruct(
        xspec(bits_indicator_tmpl, unsigned_t, 0),
        xpubb(inc::bits_indicator<bits_indicator_tmpl<unsigned_t>>),
        xpubb(inc::disable_copy),
        xprif(m_bmp          , unsigned_t *),
        xprif(m_height       , unsigned_t),
        xpric(m_need_free    , 1, unsigned_t),
        xpric(m_size         , xbitsof(unsigned_t) - 1, unsigned_t),
        xprif(m_total_bits   , unsigned_t)
    )
    public:
        xprops()
            friend inc::bits_indicator<the_t>;

            /* 属性：位图树的高度 */
            xproget_priset(height, unsigned_t);
            xproget_priset(size, unsigned_t);

            /* 属性：位图树存放位图的首地址 */
            xproget_priset(bmp, unsigned_t *);

            /* 属性：是否需要在析构时释放内存 */
            xpriget_priset(need_free, bool);

            /* 属性：位图树每一级的元素个数
             * 补充：lut[0] 表示第一级位图字的个数，对于 64bit 系统一个字有 64bit
             *       位图是分层的，在 64bit 系统，上层用 1bit 表示下层 64bit 位组中是否有置位位
             *       该属性的每一个元素分别指示了每次层一共有多少个字
             */
            xprogetx(level_lut, unsigned_t *){
                xr{ return xthe.m_bmp - xthe->height; }
            };

            /* 属性：动态内存部分一共有多少个字 */
            xprigetx(cost_count, unsigned_t){
                xr{ return xthe->size + xthe->height; }
            };

            /* 属性：动态内存部分一共包含多少个字节 */
            xpubgetx(cost_bytes, inc::memory::size){
                xr{ return inc::memory::size(xthe->cost_count * sizeof(unsigned_t)); }
            };

            /* 属性：位图可访问的总位数 */
            xpubget_priset(total_bits, uxx);
        $

        xprops_operator()

    public:
        bits_indicator_tmpl() : 
            m_bmp(nullptr), m_height(0), m_need_free(0), m_size(0), m_total_bits(0){}

        bits_indicator_tmpl(the_t && self) : 
            m_bmp(self.m_bmp),
            m_height(self.m_height),
            m_need_free(self.m_need_free),
            m_size(self.m_size),
            m_total_bits(self.m_total_bits) {

            self.m_bmp              = nullptr;
            self.m_height           = 0;
            self.m_need_free        = false;
            self.m_size             = 0;
            self.m_total_bits       = 0;
        }

        /* 函数：构造函数（外部分配内存）
         * 参数：
         * - total_bits 为位图树的总位数
         * - alloc 为分配回调函数，期望签名如下
         *      uxx * alloc(uxx length);
         * 注意：
         * - 该方式需要外部释放内存
         */
        bits_indicator_tmpl(uxx total_bits, inc::ialloc<uxx> alloc){
            uxx buf[xbitsof(unsigned_t)];

            // 先设置，之后 total_bits 会被修改
            xthe->total_bits        = total_bits;
            xthe->height            = 0;
            xthe->size              = 0;
            xthe->need_free = false;

            do{
                total_bits          = total_bits / xbitsof(unsigned_t) + (total_bits % xbitsof(unsigned_t) != 0);
                buf[xthe.m_height]  = total_bits;
                xthe.m_height      += 1;
                xthe.m_size        += total_bits;
            }while(total_bits > 1);

            auto buffer             = alloc(xthe->cost_count);
            xthe->bmp               = buffer + xthe->height;

            for(uxx i = 0; i < xthe->height; i++){
                xthe->level_lut[i]  = buf[i];
            }

            inc::zeros(xthe->bmp, xthe->size * sizeof(uxx));
        }

        /* 函数：构造函数（内部分配内存）
         * 参数：
         * - total_bits 为位图树的总位数
         * 注意：
         * - 该方式由内部释放内存
         */
        bits_indicator_tmpl(uxx total_bits) : 
            bits_indicator_tmpl(total_bits, [](uxx length){
                return inc::memory::alloc<uxx>(
                    inc::memory::size{
                        sizeof(uxx) * length
                    }
                );
            }){
            xthe->need_free = true;
        }

        ~bits_indicator_tmpl(){
            if (not xthe->need_free){
                return;
            }

            auto bytes = xthe->cost_bytes();
            auto ptr   = inc::atom_swap<uxx *>(& m_bmp, nullptr);

            if (ptr != nullptr){
                inc::memory::free(ptr - xthe->height, bytes);
            }
        }
    $

    template<uxx bits_v = 0>
    using bits_indicator = bits_indicator_tmpl<uxx, bits_v>;

    template<uxx bits_v = 0>
    using bits_indicator32 = bits_indicator_tmpl<u32, bits_v>;

    template<uxx bits_v = 0>
    using bits_indicator64 = bits_indicator_tmpl<u64, bits_v>;
}

#endif

xexport_space(mixc::utils_bits_indicator::origin)
